package app_log

import (
	"app-box/config"
	"log"
	"strings"
	"time"

	"github.com/google/uuid"
)

type LogLevel uint8

const (
	LogLevelDebug   LogLevel = 0
	LogLevelLog     LogLevel = 1
	LogLevelWarning LogLevel = 2
	LogLevelError   LogLevel = 3
	LogLevelFatal   LogLevel = 4
)

type LogMessage struct {
	Message     string    // Log message
	MessageFlag string    // A flag to mark the message type,you can custom it.
	Date        time.Time // The time that log was created.
	Level       LogLevel
}

type LogReciver struct {
	Flag string
}

var DefaultLogReciver = LogReciver{Flag: MessageTypeServerError}

func newLogMessage(flag, message string, level LogLevel) LogMessage {
	var msg LogMessage
	msg.Message = message
	msg.MessageFlag = ""
	msg.Date = time.Now()
	msg.Level = level
	return msg
}

type Logger interface {
	// this method will call by goroutine, please make sure it is thread safe.
	Log(message LogMessage)
	// call when the logger is successe registed.
	LoggerDidRegistered()
	// call when the logger is successe unregisted.
	LoggerDidUnRegistered()
}

var loggers map[string]Logger
var consoleLogger = &ConsoleLogger{}

func init() {
	loggers = make(map[string]Logger)
}

func RegisterLogger(logger Logger) (id string) {
	id = uuid.New().String()
	loggers[id] = logger
	logger.LoggerDidRegistered()
	return
}

func UnRegisterLogger(id string) {
	var logger, ok = loggers[id]
	if ok {
		delete(loggers, id)
		logger.LoggerDidUnRegistered()
	}
}

func printLog(message LogMessage) {
	for _, logger := range loggers {
		go logger.Log(message)
	}
	if config.NotReleaseMode() || message.Level == LogLevelFatal {
		consoleLogger.Log(message) // 在非发布模式和出现致命错误的时候输出错误到控制台
	}
	if message.Level == LogLevelFatal {
		time.Sleep(3 * time.Second) // 等待3秒，让有可能存在的异步loger调用完成，再退出
		log.Fatal()
	}
}

func (r LogReciver) Debug(message ...string) {
	var msg = newLogMessage(r.Flag, strings.Join(message, " "), LogLevelDebug)
	printLog(msg)
}

func (r LogReciver) Log(message ...string) {
	var msg = newLogMessage(r.Flag, strings.Join(message, " "), LogLevelLog)
	printLog(msg)
}

func (r LogReciver) Warning(message ...string) {
	var msg = newLogMessage(r.Flag, strings.Join(message, " "), LogLevelWarning)
	printLog(msg)
}

func (r LogReciver) Error(message ...string) {
	var msg = newLogMessage(r.Flag, strings.Join(message, " "), LogLevelError)
	printLog(msg)
}

func (r LogReciver) Fatal(message ...string) {
	var msg = newLogMessage(r.Flag, strings.Join(message, " "), LogLevelFatal)
	printLog(msg)
}

func (r LogReciver) NewFlag(flga string) LogReciver {
	r.Flag = flga
	return r
}

func Debug(message ...string) {
	DefaultLogReciver.Debug(message...)
}

func Log(message ...string) {
	DefaultLogReciver.Log(message...)
}

func Warning(message ...string) {
	DefaultLogReciver.Warning(message...)
}

func Error(message ...string) {
	DefaultLogReciver.Error(message...)
}

func Fatal(message ...string) {
	DefaultLogReciver.Fatal(message...)
}
